import { sleep } from '@gnlab/utils'
import { useObservable } from '@gnlab/utils/env-react/rx'
import { message } from 'antd'
import services from '@/services'
import type { ExternalContact, ExternalExtra } from '@/services/contact-types'

/**
 * 加载/刷新联系人资料
 */
export function useInfo(contactId: string) {
  const [base, setBase] = useState<ExternalContact | null>(null)
  const loadBase = useCallback(() => setBase(services.externals.getById(contactId)), [contactId])

  const [extra, setExtra] = useState<ExternalExtra | null>(null)
  const loadExtra = useCallback(async () => {
    const res = await services.externals.getExtra(contactId)
    if (res.success) setExtra(res.data)
  }, [contactId])

  const loadInfo = useCallback(() => {
    setBase(null)
    setExtra(null)
    void loadBase()
    void loadExtra()
  }, [loadBase, loadExtra])

  useEffect(() => void loadInfo(), [loadInfo])

  return {
    base,
    extra,
    updateExtra: setExtra,
    refresh: loadInfo,
  }
}

// ================================================

/**
 * 处理对联系人资料的更新
 */
export function useUpdateInfo(
  contactId: string,
  extra: ExternalExtra | null, // 当前的 extra 信息
  onUpdated: (updated: ExternalExtra) => void, // 资料被更新时触发此回调
) {
  const [updating, setUpdating] = useState<string | false>(false)

  const update = useCallback(
    async (values: ExternalExtra) => {
      if (!extra) return

      const remark = values.remark.trim()
      const corpRemark = values.corpRemark.trim()
      const desc = values.describe.trim()
      const phones = values.phoneList.map(phone => phone.trim()).filter(v => v)

      // 这里只能依次调用，因为底层目前做不到并发修改多个字段
      if (remark !== extra.remark) {
        setUpdating('正在保存：备注名...')
        await updaters.remark(contactId, remark)
        await sleep(1000)
      }
      if (corpRemark !== extra.corpRemark) {
        setUpdating('正在保存：企业...')
        await updaters.corpRemark(contactId, corpRemark)
        await sleep(1000)
      }
      if (desc !== extra.describe) {
        setUpdating('正在保存：描述...')
        await updaters.desc(contactId, desc)
        await sleep(1000)
      }
      if (JSON.stringify(phones) !== JSON.stringify(extra.phoneList)) {
        setUpdating('正在保存：电话...')
        await updaters.phones(contactId, phones)
        await sleep(1000)
      }
      setUpdating(false)

      // 执行更新后并不能马上调接口取得最新的数据，只能临时用此回调提供的最新值填充到数据里
      onUpdated(values)
    },
    [contactId, extra, onUpdated],
  )

  return [updating, update] as const
}

const updaters = {
  async remark(contactId: string, remark: string) {
    const res = await services.externals.updateRemark(contactId, remark)
    if (!res.success) void message.warning(`客户备注名保存失败：${res.error}`)
  },
  async corpRemark(contactId: string, corpRemark: string) {
    const res = await services.externals.updateCorpRemark(contactId, corpRemark)
    if (!res.success) void message.warning(`公司名保存失败：${res.error}`)
  },
  async desc(contactId: string, desc: string) {
    const res = await services.externals.updateDescribe(contactId, desc)
    if (!res.success) void message.warning(`客户描述保存失败：${res.error}`)
  },
  async phones(contactId: string, phones: string[]) {
    const res = await services.externals.updatePhones(contactId, phones)
    if (!res.success) void message.warning(`电话保存失败：${res.error}`)
  },
}

// ================================================

/**
 * 处理标签绑定
 */
export function useTags(contactId: string) {
  const [boundTags, setBoundTags] = useState<{ id: string; name: string }[] | null>(null)

  const load = useCallback(async () => {
    const res = await services.externals.tags.getBoundTags(contactId)
    if (res.success) setBoundTags(res.data)
    else void message.warning(`客户标签加载失败：${res.error}`)
  }, [contactId])
  useEffect(() => void load(), [load])

  // 刷新标签（会触发与 hook 的同步）
  const refreshingRef = useRef(false)
  const refresh = useCallback(async () => {
    if (refreshingRef.current) return // 避免用户连点刷新
    refreshingRef.current = true
    const res = await services.externals.tags.refreshBoundTags(contactId)
    refreshingRef.current = false
    if (res.success) setBoundTags(res.data)
  }, [contactId])

  // 更新绑定标签列表
  const bind = useCallback(
    (tags: { id: string; name: string }[]) => {
      void services.externals.tags.setBoundTags(
        contactId,
        tags.map(v => v.id),
      )
      setBoundTags(tags)
    },
    [contactId],
  )

  return {
    boundTags,
    loadTags: load,
    refreshTags: refresh,
    bindTags: bind,
  }
}

// ================================================

/**
 * 若客户端更新了当前客户的资料，触发回调
 */
export function useDetectUpdateByClient(contactId: string, onUpdateByClient: () => void) {
  useObservable(
    services.externals.events,
    ({ contactId: updatedId }) => {
      if (updatedId === contactId) onUpdateByClient()
    },
    [onUpdateByClient, contactId],
  )
}
